<template>
  <div class="part-left">
    <div class="tree-title" v-if="treeTitle">
      <span>{{ treeTitle }}</span>
      <el-tooltip content="刷新" placement="bottom">
        <i class="vc-icon vc-icon-refresh" @click="refresh"></i>
      </el-tooltip>
    </div>

    <div class="tree-empty" v-if="addable && !treeData.length && data !== null">
      <div>
        <span>{{ emptyText }}</span>
        <el-button type="primary" size="small" @click="add">新增</el-button>
      </div>
    </div>

    <template v-else>
      <el-input
        v-if="searchable && treeData.length"
        v-model="filterText"
        placeholder="请输入关键字"
        class="vc-search-input"
        size="small"
        clearable
      >
      </el-input>

      <el-tree
        ref="sideTree"
        class="org-tree"
        :data="treeData"
        :props="props"
        :node-key="nodeKey"
        :empty-text="data === null ? '' : emptyText"
        :expand-on-click-node="false"
        :highlight-current="true"
        :render-after-expand="true"
        :filter-node-method="filterNode"
        :default-expanded-keys="expandedKeys"
        @node-click="handleNodeClick"
      >
        <span
          class="slot-scope"
          slot-scope="{ node, data }"
          @mouseenter="point = data"
          @mouseleave="point = null"
          v-if="handleMenu"
        >
          <span>
            <i
              :class="typeof nodeIcon === 'string' ? nodeIcon : nodeIcon(data)"
            ></i>
            <span>{{ node.label }}</span>
          </span>
          <i
            v-if="
              point == data ||
              (!point &&
                data[nodeKey] == currHandleData[nodeKey] &&
                menuVisible)
            "
            class="vc-icon vc-icon-more"
            @click.stop="showHandleMenu(data, $event)"
          ></i>
        </span>

        <span class="slot-tree" slot-scope="{ node }" v-else>
          <i
            :class="typeof nodeIcon === 'string' ? nodeIcon : nodeIcon(data)"
          ></i>
          <span>{{ node.label }}</span>
        </span>
      </el-tree>
    </template>

    <ul id="menuCM" class="menu-handle-right" :style="pos" v-show="menuVisible">
      <li
        v-for="item in menuEvents"
        :key="item.name"
        @click="item.event(currHandleData)"
      >
        {{ item.name }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'el-tree-sider',
  props: {
    // 树列表标题
    treeTitle: {
      type: String,
      default: ''
    },
    // 树结构展示数据
    data: {
      type: Array,
      default () {
        return null
      }
    },
    // 配置选项
    props: {
      type: Object,
      default () {
        return {
          id: 'id',
          label: 'name',
          children: 'children',
          isLeaf: 'isLeaf'
        }
      }
    },
    // 每个树节点用来作为唯一标识的属性
    nodeKey: {
      type: String,
      default: 'id'
    },
    // 树节点图标
    nodeIcon: {
      type: [String, Function],
      default: ''
    },
    // 内容为空的时候展示的文本
    emptyText: {
      type: String,
      default: '暂无数据'
    },
    // 默认选中节点
    defaultCheckedNode: {
      type: Object,
      default () {
        return {}
      }
    },
    // 默认展开的节点 key 数组
    defaultExpandedKeys: {
      type: Array,
      default () {
        return []
      }
    },
    // 鼠标悬浮在节点上时 是否显示操作菜单
    handleMenu: {
      type: Boolean,
      default: false
    },
    // 操作菜单子选项
    menuEvents: {
      type: Array,
      default () {
        return []
      }
    },
    // 是否可搜索
    searchable: {
      type: Boolean,
      default: true
    },
    // 节点是否可选
    selectable: {
      type: Function,
      default: null
    },
    // 无数据时是否显示'新增'按钮
    addable: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      treeData: [],
      expandedKeys: [],
      currCheckedKey: '',
      currHandleData: {},
      point: null,
      menuVisible: false,
      pos: {},
      filterText: ''
    }
  },
  watch: {
    data: {
      handler (val) {
        if (val === null) {
          return
        }
        let expandedKeys = this.$refs.sideTree && this.$refs.sideTree.store._getAllNodes().filter(item => item.expanded == true).map(item => item.key)
        this.treeData = JSON.parse(JSON.stringify(val))
        if (!this.currCheckedKey) {
          this.expandedKeys = this.defaultExpandedKeys
          this.handleNodeClick(this.defaultCheckedNode, true)
          return
        }
        this.expandedKeys = expandedKeys
        let checked = this.GLOBAL.array.deepTraversal(val).filter(item => item.id == this.currCheckedKey)
        if (!checked.length) {
          this.handleNodeClick(this.defaultCheckedNode, true)
          return
        }
        this.handleNodeClick(checked[0])
      },
      immediate: true,
      deep: true
    },
    filterText (val) {
      this.$refs.sideTree.filter(this.GLOBAL.filter.filterSpace(val))
    }
  },
  mounted () {
    document.addEventListener('mousedown', this.mousedown)
    $('.org-tree').scroll(() => { this.hideMenu() })
  },
  beforeDestroy () {
    document.removeEventListener('mousedown', this.mousedown)
  },
  methods: {
    /**
     * 刷新树列表数据
     */
    refresh () {
      this.filterText = ''
      this.$emit('refresh')
    },
    /**
     * 树节点被点击时的回调
     */
    handleNodeClick (data, node) {
      if (this.selectable && !this.selectable(data)) {
        this.$nextTick(() => { this.$refs.sideTree && this.$refs.sideTree.setCurrentKey(this.currCheckedKey) })
        return
      }
      this.$nextTick(() => { this.$refs.sideTree && this.$refs.sideTree.setCurrentKey(data[this.nodeKey]) })
      this.currCheckedKey = data[this.nodeKey]
      this.$emit('node-click', data, node)
    },
    /**
     * 显示树节点操作菜单
     */
    showHandleMenu (data, ev) {
      this.currHandleData = Object.assign({}, data)
      let pos = ev.clientY + $('#menuCM').outerWidth() < innerHeight ? {
        top: ev.clientY + 'px',
        bottom: 'auto'
      } : {
        top: 'auto',
        bottom: innerHeight - ev.clientY + 'px'
      }
      pos.left = ev.clientX + 'px'
      this.pos = pos
      this.$emit('show-menu', data)
      this.menuVisible = true
    },
    /**
     * 隐藏操作菜单
     */
    hideMenu () {
      this.menuVisible = false
    },
    /**
     * 鼠标点击触发事件
     */
    mousedown (ev) {
      if (!this.menuVisible) return
      let pid = ev.target.parentElement.id
      if (pid !== 'menuCM') return this.hideMenu()
      if (ev.button !== 0) return
      ev.target.click()
      this.hideMenu()
    },
    /**
     * 对树节点进行筛选
     */
    filterNode (value, data) {
      if (!value) return true
      return data[this.props.label].indexOf(value) !== -1
    },
    /**
     * 点击'新增'按钮触发方法
     */
    add () {
      this.$emit('add')
    }
  }
}
</script>

<style lang="less" scoped>
.part-left {
  .tree-empty {
    width: 100%;
    height: calc(100% - 40px);
    display: flex;
    justify-content: center;
    align-items: center;
    & > div > span {
      display: block;
      margin-bottom: 15px;
    }
  }
}
</style>
